package com.google.location.im.ui;

import java.util.Hashtable;

import javax.microedition.lcdui.Canvas;
import javax.microedition.lcdui.Command;
import javax.microedition.lcdui.CommandListener;
import javax.microedition.lcdui.Displayable;
import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;
import javax.microedition.lcdui.game.GameCanvas;

import com.google.location.im.util.GoogleMaps;
import com.google.location.im.util.Preferences;

/**
 * @author tharindu
 */
public class MapCanvas extends GameCanvas implements CommandListener, Runnable
{

    private MainUI ui_;

    private Hashtable commands_;

    private GoogleMaps gMap_;
    
    private Graphics graphics_;

    private String location_;

    // the map image
    private Image mapImg;

    // the map image coordinates
    private int mapX = 0;
    private int mapY = 0;

    // the distance to move in the x and y axis
    private int dx = 1;
    private int dy = 1;

    // the center of the screen
    public final int CENTER_X = getWidth() / 2;
    public final int CENTER_Y = getHeight() / 2;

    // the width / height of the screen
    public final int WIDTH = getWidth();
    public final int HEIGHT = getHeight();
    
    // the pixel deviation in pixels
    private int deviationX = 0;
    private int deviationY = 0;

    // image format
    public final String format = "png32";

    private double latitude;
    private double longitude;

    // zoom level of the map
    private int zoomlevel;
    
    private boolean loading = false;

    public MapCanvas(String title, Image image)
    {
        super(true);
        ui_ = MainUI.getInstance();
        commands_ = ui_.getCommands();
        
        mapX = CENTER_X;
        mapY = CENTER_Y;
        zoomlevel = 6;
        try {
            setCommandListener(this);
        } catch (Exception e) {
            e.printStackTrace();
        }

        gMap_ = new GoogleMaps(Preferences.MAP_KEY);
        graphics_ = getGraphics();
        addCommand((Command) commands_.get(new Integer(MainUI.CMD_BACK)));
    }

    public void init(Image image)
    {
        this.mapImg = image;
    }

    public void init(String location)
    {
        if (mapImg == null) {
            location_ = location;
            Thread contr = new Thread()
            {
                public void run()
                {
                    try {
                        loading = true;
                        double[] lanLng = gMap_.geocodeAddress(location_);
                        latitude = lanLng[0];
                        longitude = lanLng[1];
                        System.out.println("[MapCanvas] latitude: " + latitude + " longitude: " + longitude);
                        Image map = gMap_.retrieveStaticImage(WIDTH + 50, HEIGHT + 50, latitude, longitude, zoomlevel, format);
                        mapImg = map; loading = false;
                        updateGameScreen(getGraphics());
                    } catch (Exception ex) {
                        System.out.println(ex.getMessage());
                    }
                }
            };
            contr.start();
        }
    }

    public void start()
    {

        mapX = CENTER_X;
        mapY = CENTER_Y;

        Thread runner = new Thread(this);
        runner.start();

    }

    public void run()
    {

        // the graphics object for this canvas
        Graphics g = getGraphics();

        while (true) { // infinite loop

            // based on the structure

            // first verify game state
            verifyGameState();

            // update screen
            updateGameScreen(graphics_);

            // and sleep, this controls
            // how fast refresh is done
            try {
                Thread.currentThread().sleep(30);
            } catch(InterruptedException ie) {
                
            }
        }

    }

    private void verifyGameState()
    {
        // doesn't do anything yet
    }

    private void updateGameScreen(Graphics g)
    {
        // the next two lines clear the background
        g.setColor(0xcdc9c9);
        g.fillRect(0, 0, WIDTH, HEIGHT);
        
        // draws the couple image according to current
        // desired positions
        g.drawImage(mapImg, mapX, mapY, Graphics.HCENTER | Graphics.VCENTER );
        // draw the center point
        g.setColor(0x000000);
        g.drawLine(CENTER_X, CENTER_Y-3, CENTER_X, CENTER_Y+3);
        g.drawLine(CENTER_X-3, CENTER_Y, CENTER_X+3, CENTER_Y);
        
        if (deviationX < -50 || deviationX > 50 || deviationY < -50 || deviationY > 50) {
            // if loading draw loading text
            g.setColor(0x00ff00);
            g.drawString("Loading...", WIDTH, 0, Graphics.TOP | Graphics.RIGHT);
        }
        // this call paints off screen buffer to screen
        flushGraphics();

    }
    
    public void keyPressed(int keycode) {
        if (!loading) {
            if (keycode == -7) {
                MainUI.hsenidCommand((Command) commands_.get(new Integer(MainUI.CMD_BACK)), this);
            } else if (keycode == RIGHT || keycode == -4) {
                mapX -= dx;
                deviationX += dx;
                updateGameScreen(graphics_);
            } else if (keycode == LEFT || keycode == -3) {
                mapX += dx;
                deviationX -= dx;
                updateGameScreen(graphics_);
            } else if (keycode == DOWN || keycode == -2) {
                mapY -= dy;
                deviationY += dx;
                updateGameScreen(graphics_);
            } else if (keycode == UP || keycode == -1) {
                mapY += dy;
                deviationY -= dy;
                updateGameScreen(graphics_);
            }
        }
    }
    
    public void keyRepeated(int keycode)
    {
        if (!loading) {
            if (keycode == RIGHT || keycode == -4) {
                mapX -= dx;
                deviationX += dx;
                updateGameScreen(graphics_);
            } else if (keycode == LEFT || keycode == -3) {
                mapX += dx;
                deviationX -= dx;
                updateGameScreen(graphics_);
            } else if (keycode == DOWN || keycode == -2) {
                mapY -= dy;
                deviationY += dx;
                updateGameScreen(graphics_);
            } else if (keycode == UP || keycode == -1) {
                mapY += dy;
                deviationY -= dy;
                updateGameScreen(graphics_);
            }
        }
    }
    
    public void keyReleased(int keycode) {
        System.out.println("[MapCanvas] keyReleased() devX: " + deviationX + " devY: " + deviationY);
        int tmpXdev, tmpYdev;
        if(deviationX < 0) {
            tmpXdev = deviationX * -1;
        } else {
            tmpXdev = deviationX;
        }
        if(deviationY < 0) {
            tmpYdev = deviationY * -1;
        } else {
            tmpYdev = deviationY;
        }
        // if any deviation exceeds 50 screen needs to redraw
        if( tmpXdev > 50 || tmpYdev > 50 ) {
            tmpXdev = deviationX; tmpYdev = deviationY;
            Thread contr = new Thread()
            {
                public void run()
                {
                    try {
                        loading = true;
                        double[] lanLng = gMap_.adjust(latitude, longitude, deviationX, deviationY, zoomlevel);
                        latitude = lanLng[0];
                        longitude = lanLng[1];
                        System.out.println("[MapCanvas] latitude: " + latitude + " longitude: " + longitude);
                        Image map = gMap_.retrieveStaticImage(WIDTH + 50, HEIGHT + 50, latitude, longitude, zoomlevel, format);
                        mapImg = map;
                        mapX = CENTER_X; mapY = CENTER_Y;
                        deviationX = 0; deviationY = 0; loading = false;
                        updateGameScreen(graphics_);
                    } catch (Exception ex) {
                        System.out.println(ex.getMessage());
                    }
                }
            };
            contr.start();
        }
    }

    public void commandAction(Command c, Displayable d)
    {
        MainUI.hsenidCommand(c, d);
    }

}
